package setCoveringProblem.gridgain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.gridgain.grid.GridException;
import org.gridgain.grid.GridJob;
import org.gridgain.grid.GridJobAdapter;
import org.gridgain.grid.GridJobResult;
import org.gridgain.grid.gridify.GridifyArgument;
import org.gridgain.grid.gridify.GridifyTaskSplitAdapter;

public class GridifyCoverTask extends GridifyTaskSplitAdapter<DatosSetCoveringProblem> { 

	/**
	 * 
	 */
	private static final long serialVersionUID = 1227101946189512505L;

	/**
	 * Este método calcula la representación binaria en forma de arreglo
	 * del número de iteración.
	 * Por Ejemplo (con 5 empleados): 
	 * 	iteración 0: 00000
	 *  iteración 1: 00001
	 *  ...
	 *  iteración 32: 11111
	 * 
	 * @param nroIteracion
	 * @param ancho
	 * @return
	 */
	private static char[] toArrayDeEmpleados(int nroIteracion, int ancho) {
		String cadenaDeBits = Long.toBinaryString(nroIteracion);
		System.out.println(cadenaDeBits);
		char[] arregloDeBits1 = new char[ancho]; 
		char[] arregloDeBits = cadenaDeBits.toCharArray();
		int atras = (ancho - arregloDeBits.length);
		for(int j = cadenaDeBits.length()-1; j>=0; j--) {
			arregloDeBits1[atras + j] = arregloDeBits[j];
		}
		return arregloDeBits1;
	}
	
	/**
	 * Este método evalúa si la combinación de empleados que recibe es 
	 * solución, o no. En caso de que sea solución, retorna la cantidad de
	 * empleados que contiene la combinación. en caso de que no sea
	 * solución, se retorna Integer.MAX_VALUE.
	 * 
	 * @param dscp parámetros de entrada.
	 * @return la cantidad de empleados (en caso de que sea solución).
	 */
	public static DatosSetCoveringProblem calcular(DatosSetCoveringProblem dscp) {
		dscp.setCantidadOptima(0);
		int skillsCubiertos = 0;
		byte[] skillACubrir = new byte[dscp.getCantidadDeSkils()];

		for(int i=0; i < dscp.getCantidadEmpleados(); i++) { 
			if ( dscp.getEmpleado(i) == '1') {
				dscp.incrementarCantidadOptima();
				for (int k=0; k<dscp.getCantidadDeSkils(); k++) {
					if (dscp.getSkillValue(i, k)==1) {
						dscp.setListaOptimaItem(i, 1) ;
						if (skillACubrir[k]==0) {
							skillsCubiertos++;
						}
						skillACubrir[k]=1;
					}
				}
			}
		}
		if (skillACubrir.length == skillsCubiertos) {

		} else {
			dscp.setCantidadOptima(Integer.MAX_VALUE);
		}		
		return dscp;
	}
	
	@Override  
	protected Collection<? extends GridJob> split(int gridSize, GridifyArgument arg) throws GridException {
		byte[][] skills = ((byte[][])arg.getMethodParameters()[0]);
		Integer numeroEmpleados = ((Integer)arg.getMethodParameters()[1]);

		/**
		 * Se calculan cuantas combinaciones exitirán dado el número de empleados.
		 * combinaciones = nro_empleados ^ 2.
		 * Si existen 10 empleados, las combinaciones posibles serán 1024
		 * y tendrán la forma:
		 * 		00000 00000
		 * 		00000 00001
		 * 		00000 00010
		 * 		...
		 * 		11111 11111
		 */
		int combinaciones = (new Double(Math.pow(2, numeroEmpleados))).intValue();
		List<GridJobAdapter<DatosSetCoveringProblem>> jobs = new ArrayList<GridJobAdapter<DatosSetCoveringProblem>>(combinaciones);

		for (int i = 0; i < combinaciones; i++) {
			/**
			 * Por cada combinación existe una representación binaria única.
			 * Como se explicó previamente.
			 */
			char[] arregloDeBits1  = toArrayDeEmpleados(i, numeroEmpleados.intValue());
			DatosSetCoveringProblem r = new DatosSetCoveringProblem(arregloDeBits1, skills);

			jobs.add(new CoverGridJobAdapter(r));
		}
		System.out.println("Termine de encolar, ahora a ejecutar..");
		return jobs;  
	}  

	/**
	 * Este método se queda con la mejor de todas las tareas que son solución.
	 */
	public DatosSetCoveringProblem reduce(List<GridJobResult> results) throws GridException {
		System.out.println("Reduciendo soluciones");
		DatosSetCoveringProblem mejorOpcion = null;

		for (GridJobResult res : results) {  
			// Cada job retorna la cantidad de empleados que contiene,
			// SI ES SOLUCIÓN.
			DatosSetCoveringProblem dscp = res.getData();  

			if (mejorOpcion == null) {
				mejorOpcion = dscp;
			} else {
				if (dscp.getCantidadOptima() == 0) {

				} else if (mejorOpcion.getCantidadOptima() > dscp.getCantidadOptima()) {
					mejorOpcion = dscp;
				}
			}
		}  	  	       
		return mejorOpcion;  
	}

}  
